package io.leo.leodata.db;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import io.leo.leoutils.ReflectUtils;
import io.leo.leoutils.StringUtils;

public class InitSqlFactory {

    public static List<String> fromBeans(Class ... beans){
        List<String> initSql = new ArrayList<>();
        for (int i=0;i<beans.length;i++){
            final Class bclz = beans[i];
            StringBuffer sql = new StringBuffer();
            final Builder builder = new Builder();
            builder.addTable(bclz.getSimpleName(),ReflectUtils.getAnnotation(bclz,IfNotExists.class)==null?false:true);
            ReflectUtils.getProperties(bclz).read(new ReflectUtils.PropertyReadCallback() {
                @Override
                public void onRead(String name, Method getter, Method setter) {
                    try {
                        Field field = bclz.getDeclaredField(name);
                        boolean unique = field.getAnnotation(Unique.class)==null?false:true;
                        boolean notnull = field.getAnnotation(NotNull.class)==null?false:true;
                        Id id  = field.getAnnotation(Id.class);
                        if (id!=null)
                            builder.addPrimaryKey(ReflectUtils.camelCaseToUnderLine(name),id.autoincrement(),notnull,unique);
                        else
                            builder.addColumn(ReflectUtils.camelCaseToUnderLine(name),getTypeStr(field.getType()),notnull,unique);

                    } catch (NoSuchFieldException e) {
                        e.printStackTrace();
                    }
                }
            });
            initSql.add(builder.build().get(0));
        }
        return initSql;
    }

    private static String getTypeStr(Class<?> type) {
        if (StringUtils.in(type.getSimpleName(),"Long","long","short","Short","Byte","byte","int","Integer","Date","Boolean","boolean"))
            return "integer";
        else if (StringUtils.in(type.getSimpleName(),"string","String","StringBuffer"))
            return "text";
        else if (StringUtils.in(type.getSimpleName(),"double","Double","float","Float"))
            return "real";
        else
            throw new RuntimeException("Type "+type.getSimpleName()+" is hasn't supported!You can try to use InitSqlFactory.Builder to build your init sql.");
    }

    public static final class Builder{
        private boolean first=true;

        private List<String> initSqls;
        private StringBuffer currentSql;

        private final static int MOT_CREATE_TABLE=0,MOT_FILL_COLUMS=1;
        private int currentMot=MOT_FILL_COLUMS;
        private Builder(){
            currentSql = new StringBuffer();
            initSqls = new ArrayList<>();
        }

        public Builder addTable(String tableName,boolean ifNotExist){

            if (first){
                first=!first;
            }else{
                currentSql.append(")");
                initSqls.add(currentSql.toString());
                currentSql.delete(0,currentSql.length()-1);
            }

            if (currentMot==MOT_CREATE_TABLE)
                throw new RuntimeException("Can't create table,because it dosen't add any colum in here..");

            currentSql.append("create table "+(ifNotExist?"if not exists ":"")+tableName+" (");
            currentMot=MOT_CREATE_TABLE;
            return this;
        }

        public Builder addPrimaryKey(String columnName,boolean autoIncrement,boolean notNull,boolean unique){
            if (currentSql.charAt(currentSql.length()-1)!='(')
                currentSql.append(",\n");
            currentSql.append(columnName+" integer primary key "+(autoIncrement?"autoincrement ":"") +(notNull?"not null ":"")+(unique?"unique ":""));
            if (currentMot!=MOT_FILL_COLUMS)
                currentMot = MOT_FILL_COLUMS;
            return this;
        }

        public Builder addInt(String columnName,boolean notNull,boolean unique){
            return addColumn(columnName,"integer",notNull,unique);
        }

        public Builder addDouble(String columnName,boolean notNull,boolean unique){
            return addColumn(columnName,"real",notNull,unique);
        }

        public Builder addText(String columnName,boolean notNull,boolean unique){
            return addColumn(columnName,"text",notNull,unique);
        }

        public Builder addBlob(String columnName,boolean notNull,boolean unique){
            return addColumn(columnName,"blob",notNull,unique);
        }
        public Builder addColumn(String columnName,String columnType,boolean notNull,boolean unique){
            if (currentSql.charAt(currentSql.length()-1)!='(')
                currentSql.append(",\n");
            currentSql.append(columnName+" "+columnType+(notNull?" not null":"")+(unique?" unique":"")+" ");
            if (currentMot!=MOT_FILL_COLUMS)
                currentMot = MOT_FILL_COLUMS;
            return this;
        }

        public List<String> build(){
            if (currentMot==MOT_CREATE_TABLE)
                throw new RuntimeException("Can't build because it dosen't add any colum in here..");
            currentSql.append(")");
            initSqls.add(currentSql.toString());
            return initSqls;
        }
    }

    public static Builder builder(){
        return new Builder();
    }
}
